package hongcheng.code_generator.config;

import java.io.File;

import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import cn.hutool.core.util.StrUtil;
import hongcheng.code_generator.entity.config.ClassConfig;
import hongcheng.code_generator.entity.config.CodeGeneratorConfig;
import hongcheng.code_generator.entity.config.CommentConfig;
import hongcheng.code_generator.entity.config.CommentConfig.DateFormatType;
import hongcheng.code_generator.entity.config.ControllerJavaConfig;
import hongcheng.code_generator.entity.config.ControllerJavaConfig.MethodRequestMapping;
import hongcheng.code_generator.entity.config.DaoJavaConfig;
import hongcheng.code_generator.entity.config.DataBaseConfig;
import hongcheng.code_generator.entity.config.EntityJavaConfig;
import hongcheng.code_generator.entity.config.OutputConfig;
import hongcheng.code_generator.entity.config.TempletFileConfig;
import hongcheng.code_generator.entity.config.TempletFileConfig.ResourceMode;
import hongcheng.code_generator.enumeration.DbNameEnum;

/**
 * 	读取并解析代码生成配置XML文件
 * */
public class DefaultXMLConfigReader extends AbstractXMLConfigReader{
	

	/**
	 * 	配置文件类缓存
	 * */
	private CodeGeneratorConfig codeGeneratorConfigCache;
	
	
	/**
	 * 	构建一个配置文件读取类实例
	 * 	@param xmlConfigFilePath 配置文件地址，绝对路径
	 * */
	public DefaultXMLConfigReader(String xmlConfigFilePath) {
		super(xmlConfigFilePath);
	}




	/** 
	 * 	解析XML文件,获取CodeGeneratorConfig对象 <br>
	 * 	如果已经读取过了，就直接返回 <br>
	 * */
	@Override
	public CodeGeneratorConfig getCodeGeneratorConfig() {
		// 如果已经读取过了，就直接返回
		if(this.codeGeneratorConfigCache != null) {
			return this.codeGeneratorConfigCache;
		}
		CodeGeneratorConfig config = new CodeGeneratorConfig();
		// 加载xml文件，生成document对象
		Document document = this.load(getXmlConfigFilePath());
		// 获取xml的数据库配置
		config.setDbConfig(this.getDBConfig(document));
		// 获取模板文件地址
		config.setTplConfig(this.getTplConfig(document));
		// 获取xml的生成文件的类名及包名的相关配置
		config.setClassConfig(this.getClassConfig(document));
		// 获取xml文件输出的相关信息
		config.setOutputConfig(this.getOutputConfig(document, config.getClassConfig()));
		// 获取xml文件注释的相关信息
		config.setCommentConfig(this.getCommentConfig(document));
		// 获取xml文件controller层代码生成配置
		config.setControllerJavaConfig(this.getControllerJavaConfig(document));
		// 获取xml文件entity实体层java代码生成配置
		config.setEntityJavaConfig(this.getEntityJavaConfig(document));
		// 获取xml文件dao层java代码生成配置
		config.setDaoJavaConfig(this.getDaoJavaConfig(document));
		// 缓存
		this.codeGeneratorConfigCache = config;
		// 返回
		return config;
	}
	
	
	/** 
	 * 	重新解析XML文件,获取CodeGeneratorConfig对象 <br>
	 * 	不管是否已经读过，都重新解析获取
	 * */
	public CodeGeneratorConfig reloadCodeGeneratorConfig() {
		// 清空缓存
		this.codeGeneratorConfigCache = null;
		// 重新读取
		return this.getCodeGeneratorConfig();
	}
	
	
	
	
	/***
	 * 	获取xml文件entity实体层java代码生成配置
	 * */
	private DaoJavaConfig getDaoJavaConfig(Document document) {
		Element rootElement = document.getRootElement();
		Element daoJavaConfigElement = rootElement.element("daoJavaConfig");
		DaoJavaConfig daoJavaConfig = new DaoJavaConfig();
		// 如果没有该节点，返回默认
		if(daoJavaConfigElement == null) {
			return daoJavaConfig;
		}
		Element method = daoJavaConfigElement.element("method");
		if(method == null) {
			return daoJavaConfig;
		}
		Element element = method.element("count");
		if(element != null) {
			if(!StrUtil.isBlank(element.attributeValue("isCreate"))){
				daoJavaConfig.setIsCreateCountMethod(Boolean.valueOf(element.attributeValue("isCreate")));
				if(!StrUtil.isBlank(element.attributeValue("methodName"))){
					daoJavaConfig.setCountMethodName(element.attributeValue("methodName"));
				}
			}
		}
		element = method.element("deleteById");
		if(element != null) {
			if(!StrUtil.isBlank(element.attributeValue("isCreate"))){
				daoJavaConfig.setIsCreateDeleteByIdMethod(Boolean.valueOf(element.attributeValue("isCreate")));
				if(!StrUtil.isBlank(element.attributeValue("methodName"))){
					daoJavaConfig.setDeleteByIdMethodName(element.attributeValue("methodName"));
				}
			}
		}
		element = method.element("getAll");
		if(element != null) {
			if(!StrUtil.isBlank(element.attributeValue("isCreate"))){
				daoJavaConfig.setIsCreateGetAllMethod(Boolean.valueOf(element.attributeValue("isCreate")));
				if(!StrUtil.isBlank(element.attributeValue("methodName"))){
					daoJavaConfig.setGetAllMethodName(element.attributeValue("methodName"));
				}
			}
		}
		element = method.element("getAllPage");
		if(element != null) {
			if(!StrUtil.isBlank(element.attributeValue("isCreate"))){
				daoJavaConfig.setIsCreateGetAllPageMethod(Boolean.valueOf(element.attributeValue("isCreate")));
				if(!StrUtil.isBlank(element.attributeValue("methodName"))){
					daoJavaConfig.setGetAllPageMethodName(element.attributeValue("methodName"));
				}
			}
		}
		element = method.element("getOneById");
		if(element != null) {
			if(!StrUtil.isBlank(element.attributeValue("isCreate"))){
				daoJavaConfig.setIsCreateGetOneByIdMethod(Boolean.valueOf(element.attributeValue("isCreate")));
				if(!StrUtil.isBlank(element.attributeValue("methodName"))){
					daoJavaConfig.setGetOneByIdMethodName(element.attributeValue("methodName"));
				}
			}
		}
		element = method.element("insertAllField");
		if(element != null) {
			if(!StrUtil.isBlank(element.attributeValue("isCreate"))){
				daoJavaConfig.setIsCreateInsertAllFieldMethod(Boolean.valueOf(element.attributeValue("isCreate")));
				if(!StrUtil.isBlank(element.attributeValue("methodName"))){
					daoJavaConfig.setInsertAllFieldMethodName(element.attributeValue("methodName"));
				}
			}
		}
		element = method.element("insertNotNullField");
		if(element != null) {
			if(!StrUtil.isBlank(element.attributeValue("isCreate"))){
				daoJavaConfig.setIsCreateInsertNotNullFieldMethod(Boolean.valueOf(element.attributeValue("isCreate")));
				if(!StrUtil.isBlank(element.attributeValue("methodName"))){
					daoJavaConfig.setInsertNotNullFieldMethodName(element.attributeValue("methodName"));
				}
			}
		}
		element = method.element("updateAllField");
		if(element != null) {
			if(!StrUtil.isBlank(element.attributeValue("isCreate"))){
				daoJavaConfig.setIsCreateUpdateAllFieldMethod(Boolean.valueOf(element.attributeValue("isCreate")));
				if(!StrUtil.isBlank(element.attributeValue("methodName"))){
					daoJavaConfig.setUpdateAllFieldMethodName(element.attributeValue("methodName"));
				}
			}
		}
		element = method.element("updateNotNullField");
		if(element != null) {
			if(!StrUtil.isBlank(element.attributeValue("isCreate"))){
				daoJavaConfig.setIsCreateUpdateNotNullFieldMethod(Boolean.valueOf(element.attributeValue("isCreate")));
				if(!StrUtil.isBlank(element.attributeValue("methodName"))){
					daoJavaConfig.setUpdateNotNullFieldMethodName(element.attributeValue("methodName"));
				}
			}
		}
		return daoJavaConfig;
	}
	
	
	
	/***
	 * 	获取xml文件entity实体层java代码生成配置
	 * */
	private EntityJavaConfig getEntityJavaConfig(Document document) {
		Element rootElement = document.getRootElement();
		Element entityJavaConfigElement = rootElement.element("entityJavaConfig");
		EntityJavaConfig entityJavaConfig = new EntityJavaConfig();
		// 如果没有该节点，返回默认
		if(entityJavaConfigElement == null) {
			return entityJavaConfig;
		}
		String isUseLombok = entityJavaConfigElement.attributeValue("isUseLombok");
		if(!StrUtil.isBlank(isUseLombok)) {
			entityJavaConfig.setisUseLombok(Boolean.valueOf(isUseLombok.trim()));
		}
		
		return entityJavaConfig;
	}
	
	
	/***
	 * 	获取xml文件controller层代码生成配置
	 * */
	private ControllerJavaConfig getControllerJavaConfig(Document document) {
		Element rootElement = document.getRootElement();
		Element controllerJavaConfigElement = rootElement.element("controllerJavaConfig");
		ControllerJavaConfig controllerJavaConfig = new ControllerJavaConfig();
		// 如果没有该节点，返回默认
		if(controllerJavaConfigElement == null) {
			return controllerJavaConfig;
		}
		Element isRestApiElement = controllerJavaConfigElement.element("isRestApi");
		if(isRestApiElement != null && !StrUtil.isBlank(isRestApiElement.getTextTrim())) {
			controllerJavaConfig.setIsRestApi(Boolean.valueOf(isRestApiElement.getTextTrim().trim()));
		}
		Element isCatchExceptionElement = controllerJavaConfigElement.element("isCatchException");
		if(isCatchExceptionElement != null && !StrUtil.isBlank(isCatchExceptionElement.getTextTrim())) {
			controllerJavaConfig.setIsCatchException(Boolean.valueOf(isCatchExceptionElement.getTextTrim().trim()));
		}
		Element methodRequestMappingElement = controllerJavaConfigElement.element("methodRequestMapping");
		if(methodRequestMappingElement != null && (controllerJavaConfig.getIsRestApi() == false || isRestApiElement == null)
				 && !StrUtil.isBlank(methodRequestMappingElement.getTextTrim())) {
			controllerJavaConfig.setIsRestApi(false);
			controllerJavaConfig.setMethodRequestMapping(MethodRequestMapping.fromRequestMapping(methodRequestMappingElement.getText().trim()));
		}
		Element isUserSwaggerElement = controllerJavaConfigElement.element("isUserSwagger");
		if(isCatchExceptionElement != null && !StrUtil.isBlank(isUserSwaggerElement.getTextTrim())) {
			controllerJavaConfig.setIsUserSwagger(Boolean.valueOf(isUserSwaggerElement.getTextTrim().trim()));
		}
		return controllerJavaConfig;
	}
	
	
	
	
	/***
	 * 	获取xml文件注释的相关信息
	 * */
	private CommentConfig getCommentConfig(Document document) {
		Element rootElement = document.getRootElement();
		
		Element outputDirXmlElement = rootElement.element("commentConfig");
		CommentConfig commentConfig = new CommentConfig();
		if(outputDirXmlElement != null) {
			Element functionComment = outputDirXmlElement.element("functionComment");
			if(functionComment != null) {
				commentConfig.setIsAddFunctionComment(StrUtil.isBlank(functionComment.getTextTrim())?true:Boolean.parseBoolean(functionComment.getTextTrim()));
			}
			Element authorComment = outputDirXmlElement.element("authorComment");
			if(functionComment != null) {
				commentConfig.setIsAddAuthorComment(StrUtil.isBlank(authorComment.getTextTrim())?true:Boolean.parseBoolean(authorComment.getTextTrim()));
				commentConfig.setAuthor(authorComment.attributeValue("author"));
			}
			Element paramComment = outputDirXmlElement.element("paramComment");
			if(functionComment != null) {
				commentConfig.setIsAddParamComment(StrUtil.isBlank(paramComment.getTextTrim())?true:Boolean.parseBoolean(paramComment.getTextTrim()));
			}
			Element returnComment = outputDirXmlElement.element("returnComment");
			if(functionComment != null) {
				commentConfig.setIsAddReturnComment(StrUtil.isBlank(returnComment.getTextTrim())?true:Boolean.parseBoolean(returnComment.getTextTrim()));
			}
			Element dateComment = outputDirXmlElement.element("dateComment");
			if(functionComment != null) {
				commentConfig.setIsAddDateComment(StrUtil.isBlank(dateComment.getTextTrim())?true:Boolean.parseBoolean(dateComment.getTextTrim()));
				String formatPattern = dateComment.attributeValue("formatPattern");
				String formatType = dateComment.attributeValue("formatType");
				if(!StrUtil.isBlank(formatPattern)) {
					commentConfig.setDateCommentFormatPattern(formatPattern.trim());
				}else {
					if(!StrUtil.isBlank(formatType)) {
						commentConfig.setDateCommentFormatPattern(DateFormatType.fromName(formatType.trim()).getDateFormatPattern());
					}
				}
			}
		}
		
		return commentConfig;
	}
	
	
	/***
	 * 	获取xml文件输出的相关信息
	 * */
	private OutputConfig getOutputConfig(Document document,ClassConfig classConfig) {
		Element rootElement = document.getRootElement();
		Element outputDirXmlElement = rootElement.element("outputDir");
		if(outputDirXmlElement == null) {
			throw new NullPointerException("XML配置文件的outputDir节点未能找到");
		}
		Attribute attribute = outputDirXmlElement.attribute("baseDir");
		if(attribute == null) {
			throw new NullPointerException("XML配置文件的baseDir节点的baseDir属性找不到");
		}
		return new OutputConfig(attribute.getText(),classConfig);
	}
	
	
	
	
	/***
	 * 	获取xml的生成文件的类名及包名的相关配置
	 * */
	private ClassConfig getClassConfig(Document document) {
		Element rootElement = document.getRootElement();
		Element classConfigXmlElement = rootElement.element("classConfig");
		if(classConfigXmlElement == null) {
			throw new NullPointerException("XML配置文件的classConfig节点未能找到");
		}
		ClassConfig classConfig = new ClassConfig();
		if(classConfigXmlElement.element("controllerClassName") != null 
				&& classConfigXmlElement.element("controllerClassName").attribute("name") != null 
				&& !StrUtil.isBlank(classConfigXmlElement.element("controllerClassName").attribute("name").getText())) {
			classConfig.setControllerClassName(classConfigXmlElement.element("controllerClassName").attribute("name").getText().trim());
		}
		if(classConfigXmlElement.element("daoClassName") != null 
				&& classConfigXmlElement.element("daoClassName").attribute("name") != null 
				&& !StrUtil.isBlank(classConfigXmlElement.element("daoClassName").attribute("name").getText())) {
			classConfig.setDaoClassName(classConfigXmlElement.element("daoClassName").attribute("name").getText().trim());
		}
		if(classConfigXmlElement.element("entityClassName") != null 
				&& classConfigXmlElement.element("entityClassName").attribute("name") != null 
				&& !StrUtil.isBlank(classConfigXmlElement.element("entityClassName").attribute("name").getText())) {
			classConfig.setEntityClassName(classConfigXmlElement.element("entityClassName").attribute("name").getText().trim());
		}
		if(classConfigXmlElement.element("mapperXMLFileName") != null 
				&& classConfigXmlElement.element("mapperXMLFileName").attribute("name") != null 
				&& !StrUtil.isBlank(classConfigXmlElement.element("mapperXMLFileName").attribute("name").getText())) {
			classConfig.setMapperXMLFileName(classConfigXmlElement.element("mapperXMLFileName").attribute("name").getText().trim());
		}
		if(classConfigXmlElement.element("packagePath") != null 
				&& classConfigXmlElement.element("packagePath").attribute("name") != null 
				&& !StrUtil.isBlank(classConfigXmlElement.element("packagePath").attribute("name").getText())) {
			classConfig.setPackagePath(classConfigXmlElement.element("packagePath").attribute("name").getText().trim());
		}
		if(classConfigXmlElement.element("serviceClassName") != null 
				&& classConfigXmlElement.element("serviceClassName").attribute("name") != null 
				&& !StrUtil.isBlank(classConfigXmlElement.element("serviceClassName").attribute("name").getText())) {
			classConfig.setServiceClassName(classConfigXmlElement.element("serviceClassName").attribute("name").getText().trim());
		}
		if(classConfigXmlElement.element("voClassName") != null 
				&& classConfigXmlElement.element("voClassName").attribute("name") != null 
				&& !StrUtil.isBlank(classConfigXmlElement.element("voClassName").attribute("name").getText())) {
			classConfig.setVoClassName(classConfigXmlElement.element("voClassName").attribute("name").getText().trim());
		}
		if(classConfigXmlElement.element("tableName") != null 
				&& classConfigXmlElement.element("tableName").attribute("name") != null 
				&& !StrUtil.isBlank(classConfigXmlElement.element("tableName").attribute("name").getText())) {
			classConfig.setTableName(classConfigXmlElement.element("tableName").attribute("name").getText().trim());
		}
		
		if(StrUtil.isBlank(classConfig.getControllerClassName()) || StrUtil.isBlank(classConfig.getDaoClassName())
				|| StrUtil.isBlank(classConfig.getEntityClassName()) || StrUtil.isBlank(classConfig.getMapperXMLFileName())
				|| StrUtil.isBlank(classConfig.getPackagePath()) || StrUtil.isBlank(classConfig.getServiceClassName())
				|| StrUtil.isBlank(classConfig.getVoClassName()) || StrUtil.isBlank(classConfig.getTableName())) {
			throw new NullPointerException("XML配置文件的classConfig节点未正确填写完整");
		}
		return classConfig;
	}
	
	
	
	
	/***
	 * 	获取xml的模板文件地址，如果找不到，则采用默认的
	 * */
	private TempletFileConfig getTplConfig(Document document) {
		// 获取根节点
		Element rootElement = document.getRootElement();
		// 获取模板文件地址节点
		Element tmpletFileConfigXmlElement = rootElement.element("tmpletFileConfig");
		// 生成模板文件地址配置类
		TempletFileConfig tplConfig = new TempletFileConfig();
		if(tmpletFileConfigXmlElement == null) {
			// 如果配置文件中节点不存在，直接返回
			return tplConfig;
		}
		// controller模板文件地址
		Element element = tmpletFileConfigXmlElement.element("controllerTplPath");
		if(element != null && element.attribute("url") != null && !StrUtil.isBlank(element.attribute("url").getText())) {
			tplConfig.setControllerTplPath(element.attribute("url").getText());
			tplConfig.setControllerTplResourceMode(ResourceMode.fromString(element.attribute("resourceMode").getText()));
		}
		// dao模板文件地址
		element = tmpletFileConfigXmlElement.element("daoTplPath");
		if(element != null && element.attribute("url") != null && !StrUtil.isBlank(element.attribute("url").getText())) {
			tplConfig.setDaoTplPath(element.attribute("url").getText());
			tplConfig.setDaoTplResourceMode(ResourceMode.fromString(element.attribute("resourceMode").getText()));
		}
		// entity模板文件地址
		element = tmpletFileConfigXmlElement.element("entityTplPath");
		if(element != null && element.attribute("url") != null && !StrUtil.isBlank(element.attribute("url").getText())) {
			tplConfig.setEntityTplPath(element.attribute("url").getText());
			tplConfig.setEntityTplResourceMode(ResourceMode.fromString(element.attribute("resourceMode").getText()));
		}
		// mapperXML模板文件地址
		element = tmpletFileConfigXmlElement.element("mapperXMLTplPath");
		if(element != null && element.attribute("url") != null && !StrUtil.isBlank(element.attribute("url").getText())) {
			tplConfig.setXmlTplPath(element.attribute("url").getText());
			tplConfig.setXmlTplResourceMode(ResourceMode.fromString(element.attribute("resourceMode").getText()));
		}else {
			// 如果没有自定义地址，则根据数据库来取内置的模板
			String dbName = rootElement.element("dataSourceConfig").element("dbName").getTextTrim();
			tplConfig.setXmlTplPathByDBName(DbNameEnum.getByLowerName(dbName));
		}
		// serviceImpl模板文件地址
		element = tmpletFileConfigXmlElement.element("serviceImplTplPath");
		if(element != null && element.attribute("url") != null && !StrUtil.isBlank(element.attribute("url").getText())) {
			tplConfig.setServiceImplTplPath(element.attribute("url").getText());
			tplConfig.setServiceImplTplResourceMode(ResourceMode.fromString(element.attribute("resourceMode").getText()));
		}
		// service模板文件地址
		element = tmpletFileConfigXmlElement.element("serviceTplPath");
		if(element != null && element.attribute("url") != null && !StrUtil.isBlank(element.attribute("url").getText())) {
			tplConfig.setServiceTplPath(element.attribute("url").getText());
			tplConfig.setServiceTplResourceMode(ResourceMode.fromString(element.attribute("resourceMode").getText()));
		}
		// queryVO模板文件地址
		element = tmpletFileConfigXmlElement.element("queryVOTplPath");
		if(element != null && element.attribute("url") != null && !StrUtil.isBlank(element.attribute("url").getText())) {
			tplConfig.setQueryVOTplPath(element.attribute("url").getText());
			tplConfig.setQueryVOTplResourceMode(ResourceMode.fromString(element.attribute("resourceMode").getText()));
		}
		return tplConfig;
	}
	
	
	
	/***
	 * 	获取xml的数据库配置
	 * */
	private DataBaseConfig getDBConfig(Document document) {
		Element rootElement = document.getRootElement();
		Element dataSourceXmlElement = rootElement.element("dataSourceConfig");
		if(dataSourceXmlElement == null) {
			throw new NullPointerException("XML配置文件的dataSourceConfig节点未能找到");
		}
		String dbName = dataSourceXmlElement.element("dbName").getTextTrim();
		String url = dataSourceXmlElement.element("url").getTextTrim();
		String userName = dataSourceXmlElement.element("username").getTextTrim();
		String password = dataSourceXmlElement.element("password").getTextTrim();
		if(StrUtil.isBlank(dbName) || StrUtil.isBlank(url) || StrUtil.isBlank(userName) || StrUtil.isBlank(password)) {
			throw new NullPointerException("XML配置文件的dataSourceConfig节点数据库连接信息为空");
		}
		return new DataBaseConfig(dbName,url,userName,password);
	}
	
	
	
	/**
	 * 	加载xml文件，生成document对象
	 * */
	private Document load(String filePath) {
		Document document = null;
		try {
			//读取指定的xml文件之后返回一个Document对象，这个对象代表了整个XML文档，用于各种Dom运算。执照XML文件头所定义的编码来转换。
			SAXReader saxReader = new SAXReader();
			//读取XML文件,获得document对象
			document = saxReader.read(new File(filePath)); 
		} catch (Exception ex) {
			ex.printStackTrace();
		}
		return document;
	}








	public CodeGeneratorConfig getCodeGeneratorConfigCache() {
		return codeGeneratorConfigCache;
	}




	public void setCodeGeneratorConfigCache(CodeGeneratorConfig codeGeneratorConfigCache) {
		this.codeGeneratorConfigCache = codeGeneratorConfigCache;
	}
	
	
}
